package com.lin.demo.aspacts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lin.demo.annotations.Resubmit;
import com.lin.demo.config.AppException;
import com.lin.demo.utils.ResubmitLocalLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpStatus;

import java.lang.reflect.Method;

/**
 * @Author zimingl
 * @Date 2023/3/31 23:41
 * @Description: 重复提交切面 java本地锁 ResubmitLocalLock
 */
//@Aspect
//@Component
public class LocalResubmitAspect {
    private final static Object REDIS_KEY = new Object();

    @Around("@annotation(com.lin.demo.annotations.Resubmit)")
    public Object handleResubmit(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //获取注解信息
        Resubmit annotation = method.getAnnotation(Resubmit.class);
        int delaySeconds = annotation.delaySeconds();
        Object[] pointArgs = joinPoint.getArgs();
        String key = "";
        //获取第一个参数
        Object firstParam = pointArgs[0];
        //解析参数
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(firstParam));
        if (jsonObject != null) {
            StringBuffer sb = new StringBuffer();
            jsonObject.forEach((k, v) -> {
                sb.append(v);
            });
            //生成加密参数 使用了content_MD5的加密方式
            key = ResubmitLocalLock.handleKey(sb.toString());
        }
        //执行锁
        boolean lock = false;
        try {
            //设置解锁key
            lock = ResubmitLocalLock.getInstance().lock(key, REDIS_KEY);
            if (lock) {
                //放行
                return joinPoint.proceed();
            } else {
                //响应重复提交异常
                throw new AppException(HttpStatus.BAD_REQUEST.value(), "请勿重复提交！");
            }
        } finally {
            //设置解锁key和解锁时间
            ResubmitLocalLock.getInstance().unLock(lock, key, delaySeconds);
        }
    }
}
